home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
hamradio
/
tnos-2.000
/
tnos-2
/
icmp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-23
|
7KB
|
287 lines
/* Internet Control Message Protocol (ICMP)
* Copyright 1991 Phil Karn, KA9Q
*/
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "icmp.h"
#if !defined(_lint) && !defined(MSDOS)
static char rcsid[] OPTIONAL = "$Id: icmp.c,v 1.8 1996/06/24 02:54:26 root Exp root $";
#endif
struct mib_entry DFAR Icmp_mib[] =
{
{ "", {0}},
{ "icmpInMsgs", {0}},
{ "icmpInErrors", {0}},
{ "icmpInDestUnreachs", {0}},
{ "icmpInTimeExcds", {0}},
{ "icmpInParmProbs", {0}},
{ "icmpInSrcQuenchs", {0}},
{ "icmpInRedirects", {0}},
{ "icmpInEchos", {0}},
{ "icmpInEchoReps", {0}},
{ "icmpInTimestamps", {0}},
{ "icmpInTimestampReps", {0}},
{ "icmpInAddrMasks", {0}},
{ "icmpInAddrMaskReps", {0}},
{ "icmpOutMsgs", {0}},
{ "icmpOutErrors", {0}},
{ "icmpOutDestUnreachs", {0}},
{ "icmpOutTimeExcds", {0}},
{ "icmpOutParmProbs", {0}},
{ "icmpOutSrcQuenchs", {0}},
{ "icmpOutRedirects", {0}},
{ "icmpOutEchos", {0}},
{ "icmpOutEchoReps", {0}},
{ "icmpOutTimestamps", {0}},
{ "icmpOutTimestampReps", {0}},
{ "icmpOutAddrMasks", {0}},
{ "icmpOutAddrMaskReps", {0}},
};
/* Process an incoming ICMP packet */
void
icmp_input (iface, ip, bp, rxbroadcast)
struct iface *iface OPTIONAL; /* Incoming interface (ignored) */
struct ip *ip; /* Pointer to decoded IP header structure */
struct mbuf *bp; /* Pointer to ICMP message */
int rxbroadcast;
{
struct icmplink *ipp;
struct mbuf *tbp;
struct icmp icmp; /* ICMP header */
struct ip oip; /* Offending datagram header */
int16 type; /* Type of ICMP message */
int16 length;
int ok_trace;
char temp[40];
icmpInMsgs++;
if (rxbroadcast) {
/* Broadcast ICMP packets are to be IGNORED !! */
icmpInErrors++;
free_p (bp);
return;
}
length = ip->length - IPLEN - ip->optlen;
if (cksum (NULLHEADER, bp, length) != 0) {
/* Bad ICMP checksum; discard */
icmpInErrors++;
free_p (bp);
return;
}
(void) ntohicmp (&icmp, &bp);
/* Process the message. Some messages are passed up to the protocol
* module for handling, others are handled here.
*/
type = (int16) icmp.type; /*lint !e571 */
switch (uchar (type)) {
case ICMP_TIME_EXCEED: /* Time-to-live Exceeded */
case ICMP_DEST_UNREACH: /* Destination Unreachable */
case ICMP_QUENCH: /* Source Quench */
switch (uchar (type)) {
case ICMP_TIME_EXCEED: /* Time-to-live Exceeded */
icmpInTimeExcds++;
break;
case ICMP_DEST_UNREACH: /* Destination Unreachable */
icmpInDestUnreachs++;
break;
case ICMP_QUENCH: /* Source Quench */
icmpInSrcQuenchs++;
break;
default:
break;
}
(void) ntohip (&oip, &bp); /* Extract offending IP header */
if (Icmp_trace) {
switch (uchar (type)) {
case ICMP_TIME_EXCEED:
ok_trace = 1;
sprintf (temp, "%s",
smsg (Exceed, NEXCEED, (unsigned) uchar (icmp.code)));
break;
case ICMP_DEST_UNREACH:
ok_trace = 1;
sprintf (temp, "%s",
smsg (Unreach, NUNREACH, (unsigned) uchar (icmp.code)));
break;
default:
ok_trace = 0;
sprintf (temp, "%u", uchar (icmp.code));
break;
}
if ((Icmp_trace == 1) || (Icmp_trace == 2 && ok_trace)) {
tcmdprintf ("ICMP from %s:", inet_ntoa (ip->source));
tcmdprintf (" dest %s %s ", inet_ntoa (oip.dest),
smsg (Icmptypes, ICMP_TYPES, (unsigned) uchar (type)));
tcmdprintf (" %s\n", temp);
}
}
for (ipp = Icmplink; ipp->funct != NULL; ipp++)
if (ipp->proto == oip.protocol)
break;
if (ipp->funct != NULL) {
(*ipp->funct) (ip->source, oip.source, oip.dest, icmp.type, icmp.code, &bp);
}
break;
case ICMP_ECHO:/* Echo Request */
/* Change type to ECHO_REPLY, recompute checksum,
* and return datagram.
*/
icmpInEchos++;
icmp.type = ICMP_ECHO_REPLY;
if ((tbp = htonicmp (&icmp, bp)) == NULLBUF) {
free_p (bp);
return;
}
icmpOutEchoReps++;
(void) ip_send (ip->dest, ip->source, ICMP_PTCL, ip->tos, 0, tbp, length, 0, 0);
return;
case ICMP_REDIRECT: /* Redirect */
icmpInRedirects++;
break;
case ICMP_PARAM_PROB: /* Parameter Problem */
icmpInParmProbs++;
break;
case ICMP_ECHO_REPLY: /* Echo Reply */
icmpInEchoReps++;
echo_proc (ip->source, ip->dest, &icmp, bp);
bp = NULLBUF; /* so it won't get freed */
break;
case ICMP_TIMESTAMP: /* Timestamp */
icmpInTimestamps++;
break;
case ICMP_TIME_REPLY: /* Timestamp Reply */
icmpInTimestampReps++;
break;
case ICMP_INFO_RQST: /* Information Request */
break;
case ICMP_INFO_REPLY: /* Information Reply */
default:
break;
}
free_p (bp);
}
/*lint -esym(18,icmp_output) */
/* Return an ICMP response to the sender of a datagram.
* Unlike most routines, the callER frees the mbuf.
*/
int
icmp_output (ip, data, type, code, args)
struct ip *ip; /* Header of offending datagram */
struct mbuf *data; /* Data portion of datagram */
char type, code; /* Codes to send */
union icmp_args *args;
{
struct mbuf *bp = NULLBUF;
struct icmp icmp; /* ICMP protocol header */
int16 dlen; /* Length of data portion of offending pkt */
int16 length; /* Total length of reply */
if (ip == NULLIP)
return -1;
if (uchar (ip->protocol) == ICMP_PTCL) {
/* Peek at type field of ICMP header to see if it's safe to
* return an ICMP message
*/
switch (uchar (data->data[0])) {
case ICMP_ECHO_REPLY:
case ICMP_ECHO:
case ICMP_TIMESTAMP:
case ICMP_TIME_REPLY:
case ICMP_INFO_RQST:
case ICMP_INFO_REPLY:
break; /* These are all safe */
default:
/* Never send an ICMP error message about another
* ICMP error message!
*/
return -1;
}
}
/* Compute amount of original datagram to return.
* We return the original IP header, and up to 8 bytes past that.
*/
dlen = len_p (data);
dlen = min (8, dlen);
length = (int16) (dlen + ICMPLEN + IPLEN + ip->optlen);
/* Take excerpt from data portion */
if (data != NULLBUF && dup_p (&bp, data, 0, dlen) == 0)
return -1; /* The caller will free data */
/* Recreate and tack on offending IP header */
if ((data = htonip (ip, bp, IP_CS_NEW)) == NULLBUF) {
free_p (bp);
icmpOutErrors++;
return -1;
}
icmp.type = type;
icmp.code = code;
icmp.args.unused = 0;
switch (uchar (icmp.type)) {
case ICMP_PARAM_PROB:
icmpOutParmProbs++;
icmp.args.pointer = args->pointer;
break;
case ICMP_REDIRECT:
icmpOutRedirects++;
icmp.args.address = args->address;
break;
case ICMP_ECHO:
icmpOutEchos++;
break;
case ICMP_ECHO_REPLY:
icmpOutEchoReps++;
break;
case ICMP_INFO_RQST:
break;
case ICMP_INFO_REPLY:
break;
case ICMP_TIMESTAMP:
icmpOutTimestamps++;
break;
case ICMP_TIME_REPLY:
icmpOutTimestampReps++;
icmp.args.echo.id = args->echo.id;
icmp.args.echo.seq = args->echo.seq;
break;
case ICMP_ADDR_MASK:
icmpOutAddrMasks++;
break;
case ICMP_ADDR_MASK_REPLY:
icmpOutAddrMaskReps++;
break;
case ICMP_DEST_UNREACH:
if (icmp.code == ICMP_FRAG_NEEDED)
icmp.args.mtu = args->mtu;
icmpOutDestUnreachs++;
break;
case ICMP_TIME_EXCEED:
icmpOutTimeExcds++;
break;
case ICMP_QUENCH:
icmpOutSrcQuenchs++;
break;
default:
break;
}
icmpOutMsgs++;
/* Now stick on the ICMP header */
if ((bp = htonicmp (&icmp, data)) == NULLBUF) {
free_p (data);
return -1;
}
return ip_send (INADDR_ANY, ip->source, ICMP_PTCL, ip->tos, 0, bp, length, 0, 0);
}